#include "status.h"
#include "mid_sysbackup.h"
#include "mid_clock.h"
#include "mid_debug.h"

flash_ssd_config_t flashSSDConfig;

const flash_user_config_t Flash_InitConfig0 = {
    .PFlashBase  = 0x00000000U,
    .PFlashSize  = 0x00080000U,
    .DFlashBase  = 0x10000000U,
    .EERAMBase   = 0x14000000U,
    .CallBack    = NULL_CALLBACK
};

#define SYSBOOT_LOG_EN 1
#if SYSBOOT_LOG_EN
#include "mid_debug.h"
#define LogMask_Backup  ((ELOG_Error | ELOG_Warning | ELOG_Trace | ELOG_Info) & LogMask_Globle)
#define backup_log(type,formate, ...) if ((type) & LogMask_Backup) DBUG_OUT(type, "Backup_log", formate, ##__VA_ARGS__)
#else
#define backup_log(type,formate, ...) (void*)0
#endif

struct_sysbackup_t g_sysbackup __attribute__((aligned(4)));

#define S32K144_SERIES
uint32_t mid_sysbackup_init(void)
{
	#if 0
	#if 1
	uint32_t error = E_OK;
	volatile uint32_t dummy_cnt = 0;
    const uint32_t max_val = 1000u;

	PCC_HAL_SetClockMode(PCC, PCC_FTFC0_CLOCK , TRUE);
	DisableInterrupts;
	
	#ifdef S32K144_SERIES
	// �ȴ��������
    while((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) != FTFC_FSTAT_CCIF_MASK);
    //����д�뻺������cache
    LMEM->PCCCR = 0x85000001;
	
    // in new "S32K144.h" file (version 4.0) MSCM_OCMDR_OCM0 is notg defined
    MSCM->OCMDR[0u] |= MSCM_OCMDR_OCM0(0xFu) | MSCM_OCMDR_OCM1(0x2u) | MSCM_OCMDR_OCM2(0xFu);

    // Without the following delay board hangs!
for (dummy_cnt = 0; dummy_cnt < max_val; ++dummy_cnt); ///< This delay seems to be necessary

	MSCM->OCMDR[1u] |= MSCM_OCMDR_OCM0(0xFu) | MSCM_OCMDR_OCM1(0x2u) | MSCM_OCMDR_OCM2(0xFu);

    // Without the following delay board hangs!
for (dummy_cnt = 0; dummy_cnt < max_val; ++dummy_cnt); ///< This delay seems to be necessary

	// in new "S32K144.h" file (version 4.0) MSCM_OCMDR_OCM2 is notg defined
	MSCM->OCMDR[2u] |= MSCM_OCMDR_OCM0(0xFu) | MSCM_OCMDR_OCM1(0xFu) | MSCM_OCMDR_OCM2(0xFu);

    // Without the following delay board hangs!
for (dummy_cnt = 0; dummy_cnt < max_val; ++dummy_cnt); ///< This delay seems to be necessary

	MSCM->OCMDR[3u] |= MSCM_OCMDR_OCM0(0xFu) | MSCM_OCMDR_OCM1(0xFu) | MSCM_OCMDR_OCM2(0xFu);

	// Without the following delay board hangs!
for (dummy_cnt = 0; dummy_cnt < max_val; ++dummy_cnt);

#endif /* S32K144_SERIES */
	//EnableInterrupts;
	
	/* Re-initialize the driver to update the new EEPROM configuration */
    error = FLASH_DRV_Init(&Flash_InitConfig0, &flashSSDConfig);
    if (error != STATUS_SUCCESS)
    {
		EnableInterrupts;
        return error;
    }
	if (flashSSDConfig.EEESize == 0u)
    {
		error = FLASH_DRV_DEFlashPartition(&flashSSDConfig, 0x02u, 0x08u, 0x0u, false, true);
        if (error != STATUS_SUCCESS)
        {
			EnableInterrupts;
			return error;
        }
        else
        {
            /* Re-initialize the driver to update the new EEPROM configuration */
            error = FLASH_DRV_Init(&Flash_InitConfig0, &flashSSDConfig);
            if (error != STATUS_SUCCESS)
            {
				EnableInterrupts;
                return error;
            }

            /* Make FlexRAM available for EEPROM */
            error = FLASH_DRV_SetFlexRamFunction(&flashSSDConfig, EEE_ENABLE, 0x00u, NULL);
            if (error != STATUS_SUCCESS)
            {
				EnableInterrupts;
                return error;
            }
        }
	}
	else
	{
		/* Make FlexRAM available for EEPROM */
	    error = FLASH_DRV_SetFlexRamFunction(&flashSSDConfig, EEE_ENABLE, 0x00u, NULL);
	    if (error != E_OK)
	    {
			EnableInterrupts;
	        return error;
	    }
	}
	EnableInterrupts;
    return error;
	#else
	uint32_t error = E_OK;
	volatile uint32_t dummy_cnt = 0;
	const uint32_t max_val = 1000u;

	PCC_HAL_SetClockMode(PCC, PCC_FTFC0_CLOCK , TRUE);
	
	DisableInterrupts;
	// �ȴ��������
    while((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) != FTFC_FSTAT_CCIF_MASK);
	
	LMEM->PCCCR = 0x85000001; /* Invalidate cache & enable write buffer, cache */
	MSCM->OCMDR[0] = 0x00000020; /* Bit 5 = 1: Enable program flash prefetch buffer */
	MSCM->OCMDR[1] = 0x00000020; /* Bit 5 = 1: Enable data flash prefetch buffer */
	EnableInterrupts;
	// Without the following delay board hangs!
	for (dummy_cnt = 0; dummy_cnt < max_val; ++dummy_cnt);
	/* Re-initialize the driver to update the new EEPROM configuration */
	error = FLASH_DRV_Init(&Flash_InitConfig0, &flashSSDConfig);
	if (error != STATUS_SUCCESS)
	{
		return error;
	}
	if (flashSSDConfig.EEESize == 0u)
	{
		error = FLASH_DRV_DEFlashPartition(&flashSSDConfig, 0x02u, 0x08u, 0x0u, false, true);
		if (error != STATUS_SUCCESS)
		{
			return error;
		}
		else
		{
			/* Re-initialize the driver to update the new EEPROM configuration */
			error = FLASH_DRV_Init(&Flash_InitConfig0, &flashSSDConfig);
			if (error != STATUS_SUCCESS)
			{
				return error;
			}

			/* Make FlexRAM available for EEPROM */
			error = FLASH_DRV_SetFlexRamFunction(&flashSSDConfig, EEE_ENABLE, 0x00u, NULL);
			if (error != STATUS_SUCCESS)
			{
				return error;
			}
		}
	}
	else
	{
		/* Make FlexRAM available for EEPROM */
		error = FLASH_DRV_SetFlexRamFunction(&flashSSDConfig, EEE_ENABLE, 0x00u, NULL);
		if (error != E_OK)
		{
			return error;
		}
	}
	return error;
	#endif
	#endif
}

uint32_t mid_sysbackup_deinit(void)
{
	return 0;
}
uint32_t mid_sysbackup_readall(void)
{
	uint32_t error = 1;


	struct_sysbackup_t * pblock = (struct_sysbackup_t *)flashSSDConfig.EERAMBase;

	g_sysbackup = *pblock;
	error = 0;
	// backup_log(ELOG_Trace, "[FLASH]read ALL data from flash ! bootVersion:0x%04X\n",g_sysbackup.g_DiagDidLogistics.bootVersion);

	//mid_sysbackup_varinit();
	
	return error;
}
typedef union{
	struct_sysbackup_t data_struct;
	uint8_t data_array[FLASH_SECTOR_SIZE];
}backup_data_t;
#if 0
status_t write_eeprom(uint32_t addroffset, uint32_t size, uint8_t * pData)
{
	status_t ret = STATUS_ERROR;        /* Store the driver APIs return code */
    uint32_t address;

	/* Try to write data to EEPROM if FlexRAM is configured as EEPROM */
    if (flashSSDConfig.EEESize != 0u)
    {
        address = flashSSDConfig.EERAMBase;
        ret = FLASH_DRV_EEEWrite(&flashSSDConfig, address + addroffset, size, pData);
        if (ret != STATUS_SUCCESS)
        {
            return ret;
        }
    }
	return ret;
}

uint32_t mid_sysbackup_writeItem(uint32_t addr, uint32_t size)
{
	uint32_t error = 0;
	status_t ret = STATUS_ERROR;

	// 1. �����������ĺϷ���
	if ((addr < (uint32_t)(&g_sysbackup)) || (addr > ((uint32_t)(&g_sysbackup) + sizeof(g_sysbackup))))
	{
		error++;
	}
	if ((addr + size) > ((uint32_t)(&g_sysbackup) + sizeof(g_sysbackup)))
	{
		error++;
	}

	if (error > 0)
	{
		backup_log(ELOG_Error, "[FLASH]Write Flash Failed!\n");
		return 1;
	}

	// 2. д��flash��
	backup_data_t * p_backup_ram = (backup_data_t *)(&g_sysbackup);
	uint32_t block_offset = (uint32_t)(addr - (uint32_t)(&g_sysbackup));
	ret = write_eeprom(block_offset, size, &p_backup_ram->data_array[block_offset]);

	return ret;
}

uint32_t mid_sysbackup_writeall(void)
{
	uint32_t error = mid_sysbackup_writeItem((uint32_t)&g_sysbackup, sizeof(g_sysbackup));

	if (error) backup_log(ELOG_Error, "[FLASH]write ALL data from flash FAILED!!!\n");
	else backup_log(ELOG_Trace, "[FLASH]write ALL data from flash success\n");
	
	return error;
}
#endif


